﻿<?xml version="1.0" encoding="UTF-8"?>
<chapter version="5" xmlns="http://docbook.org/ns/docbook"
         xmlns:xlink="http://www.w3.org/1999/xlink"
         xmlns:ns5="http://www.w3.org/1998/Math/MathML"
         xmlns:ns4="http://www.w3.org/2000/svg"
         xmlns:ns3="http://www.w3.org/1999/xhtml"
         xmlns:ns="http://docbook.org/ns/docbook">
  <title>Common Logging</title>

  <section xml:id="logging-abstract">
    <title>Introduction</title>

    <para>There are a variety of logging implementations for .NET currently in
    use, log4net, Enterprise Library Logging, NLog, to name the most popular.
    The downside of having differerent implementation is that they do not
    share a common interface and therefore impose a particular logging
    implementation on the users of your library. To solve this dependency
    problem the Common.Logging library introduces a simple abstraction to
    allow you to select a specific logging implementation at runtime.</para>

    <para>The library is based on work done by the developers of IBatis.NET
    and it's usage is inspired by log4net. Many thanks to the developers of
    those projects! The library is available for .NET 1.0, 1.1, and 2.0 with
    both debug and strongly signed release assemblies.</para>

    <para>The base logging library, Common.Logging, provides the base logging
    interfaces that appear in your code and also include simple console and
    trace based logger implementations. The libraries are located under
    bin/net/&lt;framework-version&gt;/debug or release.</para>

    <para>The following logging systems are supported out of the box:</para>

    <para><itemizedlist>
        <listitem>
          <para>System.Console</para>
        </listitem>

        <listitem>
          <para>System.Diagnostics.Trace</para>
        </listitem>

        <listitem>
          <para>Log4Net 1.2.9</para>
        </listitem>

        <listitem>
          <para>Log4Net 1.2.10 (higher version by assembly version
          redirect)</para>
        </listitem>

        <listitem>
          <para>NLog</para>
        </listitem>

        <listitem>
          <para>Enterprise Library 3.1 Logging</para>
        </listitem>

        <listitem>
          <para>Enterprise Library 4.1 Logging</para>
        </listitem>
      </itemizedlist>There are two enterprise log4net implementations, one for
    log4net 1.2.9 and another for log4net 1.2.10. The need for two log4net
    versions is due to the fact that each is signed with a different strong
    key making assembly redirection impossible.</para>

    <para>Note that it is not the intention of this library to be a
    replacement for the many fine logging libraries that are out there. The
    API is incredibly minimal and will very likely stay that way. Only use
    this library if you truly need to support multiple logging APIs.</para>
  </section>

  <section>
    <title>Upgrading from previous versions</title>

    <section>
      <title>Upgrading to 2.0</title>

      <para>The new version of Common.Logging assembly is 100% binary
      backwards compatible to previous versions. Either you rebuild your
      project against the new version or simply specifiy an assembly version
      redirect:</para>

      <para><programlisting language="xml">&lt;configuration&gt;
  &lt;runtime&gt;
     &lt;assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"&gt;
        &lt;dependentAssembly&gt;
           &lt;assemblyIdentity name="Common.Logging" publicKeyToken="af08829b84f0328e" /&gt;
           &lt;bindingRedirect oldVersion="0.0.0.0-65535.65535.65535.65535" newVersion="2.0.0.0"/&gt;
           &lt;!-- reference specific file: --&gt;
           &lt;!-- codeBase version="2.0.0.0" href="../../../build/net/2.0/release/Common.Logging.dll"/ --&gt;
        &lt;/dependentAssembly&gt;
     &lt;/assemblyBinding&gt;
  &lt;/runtime&gt;
&lt;/configuration&gt;</programlisting>Those who implemented their own
      <interfacename>Common.Logging.ILoggerFactoryAdapter</interfacename> and
      <interfacename>Common.Logging.ILog</interfacename> interfaces, need to
      update their code to the extended interfaces coming with version 2.0.
      For convenience Common.Logging comes with a couple of support classes,
      making this task as easy as possible as described in <link
      linkend="logging-advanced-customfactoryadapter">Implementing a custom
      FactoryAdapter</link></para>
    </section>
  </section>

  <section xml:id="logging-usage">
    <title>Using Common.Logging API</title>

    <para>Usage of the Logging API is fairly simple. First you need to obtain
    a logger from the LogManager and call the appropriate logging method:
    <programlisting language="csharp">using Common.Logging;
...
ILog log = LogManager.GetCurrentClassLogger();
log.Debug("hello world");</programlisting></para>

    <para>It is also possible to obtain a logger by name: <programlisting
    language="csharp">ILog log = LogManager.GetLogger("mylogger");</programlisting></para>

    <para>When working on NET 3.0 or higher, a logger offers a convenient way
    to log information while paying as little performance penalty as possible.
    Sometimes evaluating log messsage arguments migth be costly. These costs
    even hit you, when the logging is turned off, just because the log call is
    in your code. In this case one usually writes:</para>

    <para><programlisting language="csharp">if (log.IsDebugEnabled)
{
  log.Debug( "my expensive to calculate argument is: {0}", CalculateMessageInfo() );
}</programlisting>Since Common.Logging 2.0 there is a shortcut notation
    available that allows you to write:</para>

    <para><programlisting>log.Debug( m=&gt;m("my expensive to calculate argument is: {0}", CalculateMessageInfo()) );</programlisting>This
    form is equivalent to the example above and guarantees, that
    <methodname>CalculateMessageInfo()</methodname> is only called, when the
    message really gets logged!</para>

    <para>Finally here is the complete interface offered by a logger instance:
    <programlisting language="csharp">public interface ILog
{
    // Methods
    void Trace(object message);
    void Trace(object message, Exception exception);
    void Trace(FormatMessageCallback formatMessageCallback);
    void Trace(FormatMessageCallback formatMessageCallback, Exception exception);
    void Trace(IFormatProvider formatProvider, FormatMessageCallback formatMessageCallback);
    void Trace(IFormatProvider formatProvider, FormatMessageCallback formatMessageCallback
               , Exception exception);
    void TraceFormat(string format, params object[] args);
    void TraceFormat(string format, Exception exception, params object[] args);
    void TraceFormat(IFormatProvider formatProvider, string format, params object[] args);
    void TraceFormat(IFormatProvider formatProvider, string format, Exception exception
                     , params object[] args);

    void Debug(object message);
    void Debug(object message, Exception exception);
    void Debug(FormatMessageCallback formatMessageCallback);
    void Debug(FormatMessageCallback formatMessageCallback, Exception exception);
    void Debug(IFormatProvider formatProvider, FormatMessageCallback formatMessageCallback);
    void Debug(IFormatProvider formatProvider, FormatMessageCallback formatMessageCallback
               , Exception exception);
    void DebugFormat(string format, params object[] args);
    void DebugFormat(string format, Exception exception, params object[] args);
    void DebugFormat(IFormatProvider formatProvider, string format, params object[] args);
    void DebugFormat(IFormatProvider formatProvider, string format, Exception exception
                     , params object[] args);

    void Info(object message);
    void Info(object message, Exception exception);
    void Info(FormatMessageCallback formatMessageCallback);
    void Info(FormatMessageCallback formatMessageCallback, Exception exception);
    void Info(IFormatProvider formatProvider, FormatMessageCallback formatMessageCallback);
    void Info(IFormatProvider formatProvider, FormatMessageCallback formatMessageCallback
              , Exception exception);
    void InfoFormat(string format, params object[] args);
    void InfoFormat(string format, Exception exception, params object[] args);
    void InfoFormat(IFormatProvider formatProvider, string format, params object[] args);
    void InfoFormat(IFormatProvider formatProvider, string format, Exception exception
                    , params object[] args);

    void Warn(object message);
    void Warn(object message, Exception exception);
    void Warn(FormatMessageCallback formatMessageCallback);
    void Warn(FormatMessageCallback formatMessageCallback, Exception exception);
    void Warn(IFormatProvider formatProvider, FormatMessageCallback formatMessageCallback);
    void Warn(IFormatProvider formatProvider, FormatMessageCallback formatMessageCallback
              , Exception exception);
    void WarnFormat(string format, params object[] args);
    void WarnFormat(string format, Exception exception, params object[] args);
    void WarnFormat(IFormatProvider formatProvider, string format, params object[] args);
    void WarnFormat(IFormatProvider formatProvider, string format, Exception exception
                    , params object[] args);

    void Error(object message);
    void Error(object message, Exception exception);
    void Error(FormatMessageCallback formatMessageCallback);
    void Error(FormatMessageCallback formatMessageCallback, Exception exception);
    void Error(IFormatProvider formatProvider, FormatMessageCallback formatMessageCallback);
    void Error(IFormatProvider formatProvider, FormatMessageCallback formatMessageCallback
               , Exception exception);
    void ErrorFormat(string format, params object[] args);
    void ErrorFormat(string format, Exception exception, params object[] args);
    void ErrorFormat(IFormatProvider formatProvider, string format, params object[] args);
    void ErrorFormat(IFormatProvider formatProvider, string format, Exception exception
                     , params object[] args);

    void Fatal(object message);
    void Fatal(object message, Exception exception);
    void Fatal(FormatMessageCallback formatMessageCallback);
    void Fatal(FormatMessageCallback formatMessageCallback, Exception exception);
    void Fatal(IFormatProvider formatProvider, FormatMessageCallback formatMessageCallback);
    void Fatal(IFormatProvider formatProvider, FormatMessageCallback formatMessageCallback
               , Exception exception);
    void FatalFormat(string format, params object[] args);
    void FatalFormat(string format, Exception exception, params object[] args);
    void FatalFormat(IFormatProvider formatProvider, string format, params object[] args);
    void FatalFormat(IFormatProvider formatProvider, string format, Exception exception
                     , params object[] args);

    // Properties
    bool IsDebugEnabled { get; }
    bool IsErrorEnabled { get; }
    bool IsFatalEnabled { get; }
    bool IsInfoEnabled { get; }
    bool IsTraceEnabled { get; }
    bool IsWarnEnabled { get; }
}</programlisting></para>

    <para>Since the ILog interface mimics that of the interface used in
    log4net, migration from log4net is just a matter of changing the 'using'
    statement.</para>

    <para>You can get a reference to an instance of an ILog using the
    LoggingManager class. Its API is shown below:</para>

    <programlisting language="csharp">public sealed class LogManager
{
  public static ILog GetLogger( Type type ) ...
  public static ILog GetLogger( string name ) ...

  public static ILoggerFactoryAdapter Adapter ...
}    </programlisting>

    <para>The Adapter property is used by the framework itself.</para>
  </section>

  <section xml:id="logging-config">
    <title>Configuring Logging</title>

    <para>There are 2 ways of configuring logging in your application - either
    declaratively or pro grammatically.</para>

    <section xml:id="logging-declarative-config">
      <title>Declarative Configuration</title>

      <para>Logging configuration can be done declaratively in your
      app.config</para>

      <programlisting language="xml">&lt;configuration&gt;
  &lt;configSections&gt;
    &lt;sectionGroup name="common"&gt;
      &lt;section name="logging" type="Common.Logging.ConfigurationSectionHandler, Common.Logging" /&gt;
    &lt;/sectionGroup&gt;
  &lt;/configSections&gt;

  &lt;common&gt;
    &lt;logging&gt;
      &lt;factoryAdapter type="Common.Logging.Simple.ConsoleOutLoggerFactoryAdapter, Common.Logging"&gt;
        &lt;arg key="level" value="DEBUG" /&gt;
        &lt;arg key="showLogName" value="true" /&gt;
        &lt;arg key="showDataTime" value="true" /&gt;
        &lt;arg key="dateTimeFormat" value="yyyy/MM/dd HH:mm:ss:fff" /&gt;
      &lt;/factoryAdapter&gt;
    &lt;/logging&gt;
  &lt;/common&gt;
&lt;/configuration&gt;      </programlisting>

      <note>
        <para>The concrete set of &lt;arg&gt; elements you may specify depends
        on the FactoryAdapter being used.</para>
      </note>

      <para>Note that if you have installed Common.Logging in the GAC, you
      will need to specify the fully qualified name of the assembly, i.e. add
      the Version, Culture, and PublicKeyToken, etc. See the log4net section
      for an example.</para>
    </section>

    <section xml:id="logging-configuring-in-code">
      <title>Configuring Logging in your code</title>

      <para>You may manually configure logging by setting a
      LoggerFactoryAdapter in your code.</para>

      <programlisting language="csharp">// create properties
NameValueCollection properties = new NameValueCollection();
properties["showDateTime"] = "true";

// set Adapter
Common.Logging.LogManager.Adapter = new Common.Logging.Simple.ConsoleOutLoggerFactoryAdapter(properties);      </programlisting>

      <note>
        <para>The concrete set of properties you may specify depends on the
        FactoryAdapter being used.</para>
      </note>
    </section>
  </section>

  <section xml:id="logging-adapters">
    <title>Logging Adapters</title>

    <para>There are simple out-of-the-box implementations coming with
    Common.Logging itself. For connecting to log4net, separate adapters do
    exist.</para>

    <note>
      <para>Be sure to correctly specify the type of the FactoryAdapter in the
      common logging configuration section and to copy the logging
      implementation .dlls to your runtime directory. At the moment, if the
      specified FactoryAdapter type is not found or its dependent libraries,
      the NoOpLoggerFactoryAdaptor is used by default and you will not see any
      logging output.</para>
    </note>

    <section xml:id="logging-noop">
      <title>NoOpLoggerFactoryAdapter</title>

      <para>This is the default FactoryAdapter if logging is not configured.
      It simply does nothing.</para>
    </section>

    <section xml:id="logging-console">
      <title>ConsoleOutLoggerFactoryAdapter</title>

      <para>ConsoleOutLoggerFactoryAdapter uses Console.Out for logging
      output.</para>

      <table conformance="" xml:id="logging-console-config-props">
        <title>Configuration Properties</title>

        <tgroup cols="3">
          <colspec colname="key" colnum="1" colwidth="1*" />

          <colspec colname="val" colnum="2" colwidth="1*" />

          <colspec colname="desc" colnum="3" colwidth="2*" />

          <thead>
            <row>
              <entry>Key</entry>

              <entry>Possible Value(s)</entry>

              <entry>Description</entry>
            </row>
          </thead>

          <tbody>
            <row>
              <entry>level</entry>

              <entry>All Debug Info Warn Error Fatal Off</entry>

              <entry>Defines the global maximum level of logging.</entry>
            </row>

            <row>
              <entry>showDateTime</entry>

              <entry>true|false</entry>

              <entry>output timestamp?</entry>
            </row>

            <row>
              <entry>showLogName</entry>

              <entry>true|false</entry>

              <entry>output logger name?</entry>
            </row>

            <row>
              <entry>dateTimeFormat</entry>

              <entry>any formatstring accepted by DateTime.ToString()</entry>

              <entry>defines the format to be used for output the timestamp.
              If no format is specified DateTime.ToString() will be
              used.</entry>
            </row>
          </tbody>
        </tgroup>
      </table>
    </section>

    <section xml:id="logging-trace">
      <title>TraceLoggerFactoryAdapter</title>

      <para>TraceLoggerFactoryAdapter uses
      <classname>System.Diagnostics.Trace</classname> for logging output. For
      viewing it's output you can use any tool that is capable of capturing
      calls to Win32 <function>OutputDebugString()</function> - e.g. the tool
      "DebugView" from <link xlink:href="www.sysinternals.com"
      xlink:title="www.sysinternals.com">www.sysinternals.com</link>.</para>

      <table>
        <title>Configuration Properties</title>

        <tgroup cols="3">
          <colspec colname="key" colnum="1" colwidth="1*" />

          <colspec colname="val" colnum="2" colwidth="1*" />

          <colspec colname="desc" colnum="3" colwidth="2*" />

          <thead>
            <row>
              <entry>Key</entry>

              <entry>Possible Value(s)</entry>

              <entry>Description</entry>
            </row>
          </thead>

          <tbody>
            <row>
              <entry>level</entry>

              <entry>All Debug Info Warn Error Fatal Off</entry>

              <entry>Defines the global maximum level of logging.</entry>
            </row>

            <row>
              <entry>showDateTime</entry>

              <entry>true|false</entry>

              <entry>output timestamp?</entry>
            </row>

            <row>
              <entry>showLogName</entry>

              <entry>true|false</entry>

              <entry>output logger name?</entry>
            </row>

            <row>
              <entry>dateTimeFormat</entry>

              <entry>any formatstring accepted by DateTime.ToString()</entry>

              <entry>defines the format to be used for output the timestamp.
              If no format is specified DateTime.ToString() will be
              used.</entry>
            </row>
          </tbody>
        </tgroup>
      </table>
    </section>

    <section xml:id="logging-adapters-log4net">
      <title>Log4NetLoggerFactoryAdapter</title>

      <para>There are two implementations, both configured similarly.</para>

      <itemizedlist>
        <listitem>
          <para><package>Common.Logging.Log4Net</package></para>

          <para>is linked against log4net 1.2.10.0</para>
        </listitem>

        <listitem>
          <para><package>Common.Logging.Log4Net129</package></para>

          <para>is linked against log4net 1.2.9.0</para>
        </listitem>
      </itemizedlist>

      <para>The only difference is in the type specified to the factory
      adapter. Both Adapters accept the following configuration
      properties:</para>

      <table xml:id="logging-log4net-config-props">
        <title>Configuration Properties</title>

        <tgroup cols="3">
          <colspec colname="key" colnum="1" colwidth="1*" />

          <colspec colname="val" colnum="2" colwidth="1*" />

          <colspec colname="desc" colnum="3" colwidth="2*" />

          <thead>
            <row>
              <entry>Key</entry>

              <entry>Possible Value(s)</entry>

              <entry>Description</entry>
            </row>
          </thead>

          <tbody>
            <row>
              <entry>configType</entry>

              <entry><para>FILE</para> <para>FILE-WATCH</para>
              <para>INLINE</para> <para>EXTERNAL</para></entry>

              <entry><para>INLINE will simply call
              XmlConfigurator.Configure()</para> <para>EXTERNAL expects
              log4net being configured somewhere else in your code and does
              nothing.</para> <para>FILE, FILE-WATCH: see property
              "configFile" below.</para></entry>
            </row>

            <row>
              <entry>configFile</entry>

              <entry>&lt;path to your log4net.config file&gt;</entry>

              <entry><para>if configType is FILE or FILE-WATCH, the value of
              "configFile" is passed to XmlConfigurator.Configure (FileInfo) /
              ConfigureAndWatch(FileInfo) method.</para></entry>
            </row>
          </tbody>
        </tgroup>
      </table>

      <para>The example below will configure log4net 1.2.10.0 using the file
      <filename>log4net.config</filename> from your application's root
      directory by calling
      <function>XmlConfigurator.ConfigureAndWatch()</function>:</para>

      <programlisting language="xml">&lt;configuration&gt;
  &lt;common&gt;
    &lt;logging&gt;
      &lt;factoryAdapter type="Common.Logging.Log4Net.Log4NetLoggerFactoryAdapter, Common.Logging.Log4net"&gt;
        &lt;arg key="configType" value="FILE-WATCH" /&gt;
        &lt;arg key="configFile" value="~/log4net.config" /&gt;
      &lt;/factoryAdapter&gt;
    &lt;/logging&gt;
  &lt;/common&gt;
&lt;/configuration&gt; </programlisting>

      <para>For log4net 1.2.9, change the assembly name
      <package>Common.Logging.Log4Net129.</package></para>

      <para>Another example that shows the log4net configuration 'inline' with
      the standard application configuration file is shown below.</para>

      <para><programlisting language="xml">&lt;configuration&gt;
  &lt;configSections&gt;
    &lt;sectionGroup name="common"&gt;
      &lt;section name="logging" type="Common.Logging.ConfigurationSectionHandler, Common.Logging" /&gt;
    &lt;/sectionGroup&gt;

    &lt;section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net"/&gt;
  &lt;/configSections&gt;

  &lt;common&gt;
    &lt;logging&gt;
      &lt;factoryAdapter type="Common.Logging.Log4Net.Log4NetLoggerFactoryAdapter, Common.Logging.Log4Net"&gt;
        &lt;arg key="configType" value="INLINE" /&gt;
      &lt;/factoryAdapter&gt;
    &lt;/logging&gt;
  &lt;/common&gt;

  &lt;log4net&gt;
    &lt;appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender"&gt;
      &lt;layout type="log4net.Layout.PatternLayout"&gt;
        &lt;conversionPattern value="%date [%thread] %-5level %logger %ndc - %message%newline" /&gt;
      &lt;/layout&gt;
    &lt;/appender&gt;

    &lt;root&gt;
      &lt;level value="DEBUG" /&gt;
      &lt;appender-ref ref="ConsoleAppender" /&gt;
    &lt;/root&gt;

    &lt;logger name="MyApp.DataAccessLayer"&gt;
      &lt;level value="DEBUG" /&gt;
    &lt;/logger&gt;
  &lt;/log4net&gt;
&lt;/configuration&gt;</programlisting></para>

      <para>Note that if you are using Common.Logging or any of the adapters
      from the GAC, you will need to specify the full type name, including
      verison, publickey token etc., as shown below</para>

      <programlisting language="xml">&lt;configSections&gt;
  &lt;sectionGroup name="common"&gt;
    &lt;section name="logging" type="Common.Logging.ConfigurationSectionHandler, Common.Logging,
                                  Version=2.0.0.0, Culture=neutral, PublicKeyToken=AF08829B84F0328E"/&gt;
  &lt;/sectionGroup&gt;
  &lt;section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net,
                                Version=1.2.10.0, Culture=neutral, PublicKeyToken=1B44E1D426115821"/&gt;
&lt;/configSections&gt;
&lt;common&gt;
 &lt;logging&gt;
   &lt;factoryAdapter type="Common.Logging.Log4Net.Log4NetLoggerFactoryAdapter, Common.Logging.Log4Net,
                         Version=2.0.2.2, Culture=neutral, PublicKeyToken=AF08829B84F0328E"&gt;
     &lt;arg key="configType" value="FILE-WATCH"/&gt;
     &lt;arg key="configFile" value="~/log4net.config"/&gt;
   &lt;/factoryAdapter&gt;
 &lt;/logging&gt;
&lt;/common&gt;</programlisting>
    </section>

    <section xml:id="logging-adapters-nlog">
      <title>NLogLoggerFactoryAdapter</title>

      <para>There is one implementation.</para>

      <itemizedlist>
        <listitem>
          <para><package>Common.Logging.NLog</package></para>

          <para>is linked against NLog 1.0.0.505</para>
        </listitem>
      </itemizedlist>

      <table xml:id="logging-nlog-config-props">
        <title>Configuration Properties</title>

        <tgroup cols="3">
          <colspec colname="key" colnum="1" colwidth="1*" />

          <colspec colname="val" colnum="2" colwidth="1*" />

          <colspec colname="desc" colnum="3" colwidth="2*" />

          <thead>
            <row>
              <entry>Key</entry>

              <entry>Possible Value(s)</entry>

              <entry>Description</entry>
            </row>
          </thead>

          <tbody>
            <row>
              <entry>configType</entry>

              <entry><para>INLINE</para> <para>FILE</para></entry>

              <entry><para>INLINE</para> <para>FILE: see property "configFile"
              below.</para></entry>
            </row>

            <row>
              <entry>configFile</entry>

              <entry>&lt;path to your NLog.config file&gt;</entry>

              <entry><para>if configType is FILE, the value of "configFile" is
              passed to XmlLoggingConfiguration(string)
              constructor.</para></entry>
            </row>
          </tbody>
        </tgroup>
      </table>

      <para>The example below will configure NLog using the file
      <filename>NLog.config</filename> from your application's root directory
      by calling <function>XmlLoggingConfiguration(string)</function>:</para>

      <programlisting language="xml">&lt;configuration&gt;
  &lt;common&gt;
    &lt;logging&gt;
      &lt;factoryAdapter type="Common.Logging.NLog.NLogLoggerFactoryAdapter, Common.Logging.NLog"&gt;
        &lt;arg key="configType" value="FILE" /&gt;
        &lt;arg key="configFile" value="~/NLog.config" /&gt;
      &lt;/factoryAdapter&gt;
    &lt;/logging&gt;
  &lt;/common&gt;
&lt;/configuration&gt; </programlisting>

      <para>Another example that shows the NLog configuration 'inline' with
      the standard application configuration file is shown below.</para>

      <para><programlisting language="xml">&lt;configuration&gt;
  &lt;configSections&gt;
    &lt;sectionGroup name="common"&gt;
      &lt;section name="logging" type="Common.Logging.ConfigurationSectionHandler, Common.Logging" /&gt;
    &lt;/sectionGroup&gt;

    &lt;section name="nlog" type="NLog.Config.ConfigSectionHandler, NLog"/&gt;
  &lt;/configSections&gt;

  &lt;common&gt;
    &lt;logging&gt;
      &lt;factoryAdapter type="Common.Logging.NLog.NLogLoggerFactoryAdapter, Common.Logging.NLog"&gt;
        &lt;arg key="configType" value="INLINE" /&gt;
      &lt;/factoryAdapter&gt;
    &lt;/logging&gt;
  &lt;/common&gt;

  &lt;nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"&gt;
    &lt;targets&gt;
      &lt;target name="console" xsi:type="Console" layout="${date:format=HH\:MM\:ss} ${logger} ${message}" /&gt;
    &lt;/targets&gt;
    &lt;rules&gt;
      &lt;logger name="*" minlevel="Debug" writeTo="console" /&gt;
    &lt;/rules&gt;
  &lt;/nlog&gt;
&lt;/configuration&gt; </programlisting></para>
    </section>

    <section>
      <title>Enterprise Library 3.1 Logging Adapter</title>

      <para>There is one implementation located in the assembly
      <classname>Common.Logging.EntLib</classname> and is linked against the
      Microsoft Enterprise Library v 3.1, aka EntLib 3.1. The .dlls for EntLib
      can not be redistributed so you will need to download EntLib
      separately.</para>

      <para>There are no configuration options for the adapter. Configuration
      of EntLib logging is done entirely though App.config. The example below
      shows the basic configuration of the EntLibLoggingAdapter</para>

      <programlisting language="xml">&lt;common&gt;
  &lt;logging&gt;
    &lt;factoryAdapter type="Common.Logging.EntLib.EntLibLoggerFactoryAdapter, Common.Logging.EntLib"/&gt;
  &lt;/logging&gt;
&lt;/common&gt;</programlisting>

      <para>Future releases may include configuration of the priority and also
      the format in which information about an exception is logged. The
      current priority used is -1, the default.</para>

      <para>Note that the following mapping of Common.Logging LogLevel to
      System.Diagnostics.TraceEventType is used.</para>

      <para><table xml:id="entlib-level-mapping">
          <title>EntLib 3.1 to Common.Logging log level mapping</title>

          <tgroup cols="2">
            <colspec colname="key" colnum="1" colwidth="1*" />

            <colspec colname="val" colnum="2" colwidth="1*" />

            <thead>
              <row>
                <entry>Common.Logging.LogLevel</entry>

                <entry>System.Diagnostics.TraceEventType</entry>
              </row>
            </thead>

            <tbody>
              <row>
                <entry>Trace</entry>

                <entry>Verbose</entry>
              </row>

              <row>
                <entry>Debug</entry>

                <entry>Verbose</entry>
              </row>

              <row>
                <entry>Error</entry>

                <entry>Error</entry>
              </row>

              <row>
                <entry>Fatal</entry>

                <entry>Critical</entry>
              </row>

              <row>
                <entry>Info</entry>

                <entry>Information</entry>
              </row>

              <row>
                <entry>Warn</entry>

                <entry>Warning</entry>
              </row>
            </tbody>
          </tgroup>
        </table></para>
    </section>

    <section>
      <title>Enterprise Library 4.1 Logging Adapter</title>

      <para>There is one implementation located in the assembly
      <classname>Common.Logging.EntLib</classname>41 and is linked against the
      Microsoft Enterprise Library v4.1, aka EntLib 4.1. The .dlls for EntLib
      can not be redistributed so you will need to download EntLib
      separately.</para>

      <para>There are no configuration options for the adapter. Configuration
      of EntLib logging is done entirely though App.config. The example below
      shows the basic configuration of the EntLibLoggingAdapter</para>

      <programlisting language="xml">&lt;common&gt;
  &lt;logging&gt;
    &lt;factoryAdapter type="Common.Logging.EntLib.EntLibLoggerFactoryAdapter, Common.Logging.EntLib41"/&gt;
  &lt;/logging&gt;
&lt;/common&gt;</programlisting>

      <para>Future releases may include configuration of the priority and also
      the format in which information about an exception is logged. The
      current priority used is -1, the default.</para>

      <para>Note that the following mapping of Common.Logging LogLevel to
      System.Diagnostics.TraceEventType is used.</para>

      <para><table xml:id="entlib41-level-mapping">
          <title>EntLib 4,1 to Common.Logging log level mapping</title>

          <tgroup cols="2">
            <colspec colname="key" colnum="1" colwidth="1*" />

            <colspec colname="val" colnum="2" colwidth="1*" />

            <thead>
              <row>
                <entry>Common.Logging.LogLevel</entry>

                <entry>System.Diagnostics.TraceEventType</entry>
              </row>
            </thead>

            <tbody>
              <row>
                <entry>Trace</entry>

                <entry>Verbose</entry>
              </row>

              <row>
                <entry>Debug</entry>

                <entry>Verbose</entry>
              </row>

              <row>
                <entry>Error</entry>

                <entry>Error</entry>
              </row>

              <row>
                <entry>Fatal</entry>

                <entry>Critical</entry>
              </row>

              <row>
                <entry>Info</entry>

                <entry>Information</entry>
              </row>

              <row>
                <entry>Warn</entry>

                <entry>Warning</entry>
              </row>
            </tbody>
          </tgroup>
        </table></para>
    </section>
  </section>

  <section xml:id="logging-advanced">
    <title>Advanced Logging Tasks</title>

    <section>
      <title>Integrating with System.Diagnostics.Trace</title>

      <para>There are 2 ways of integrating with
      <classname>System.Diagnostics.Trace</classname>: Either you redirect all
      log messages from <classname>System.Diagnostics.Trace</classname> to
      <classname>Common.Logging</classname> or vice versa. Logging from
      <classname>Common.Logging</classname> to
      <classname>System.Diagnostics.Trace</classname> is done by configuring
      <link linkend="logging-trace">TraceLoggerFactoryAdapter</link>.</para>

      <para>To configure <classname>System.Diagnostics.Trace</classname> to
      route its output to the <classname>Common.Logging</classname>
      infrastructure, you need to configure a special
      <classname>TraceListener</classname>:</para>

      <para><programlisting language="xml">&lt;configuration&gt;
   &lt;system.diagnostics&gt;
      &lt;trace&gt;
         &lt;listeners&gt;
            &lt;clear /&gt;
            &lt;add name="commonLoggingListener"
                 type="Common.Logging.CommonLoggingTraceListener, Common.Logging"
                 initializeData="LogLevel=Trace" /&gt;
         &lt;/listeners&gt;
      &lt;/trace&gt;
   &lt;/system.diagnostics&gt;
&lt;/configuration&gt;</programlisting>This configuration causes all messages
      logged via <classname>System.Diagnostics.Trace.Write</classname> to be
      logged using a logger instance obtained from
      <classname>LogManager</classname> by the "name" attribute and using the
      LogLevel specified in the "initializeData" attribute.</para>
    </section>

    <section xml:id="logging-advanced-customfactoryadapter">
      <title>Implementing a custom FactoryAdapter</title>

      <para>f you want to plug in a new, yet unsupported logging library, you
      need to provide a logger factory adapter that implementes the
      <interfacename>Common.Logging.ILoggerFactoryAdapter</interfacename>
      interface. Loggers must implement the
      <interfacename>Common.Logging.ILog</interfacename> interface.</para>

      <para><guilabel>Important:</guilabel> Any implementation
      <emphasis>must</emphasis> provide a public constructor accepting a
      <classname>NameValueCollection</classname> parameter as shown in the
      example below:<programlisting language="csharp">public class MyLoggingFactoryAdapter :  ILoggerFactoryAdapter
{
  public MyLoggingFactoryAdapter(NameValueCollection properties)
  {
    // configure according to properties
  }

  public ILog GetLogger(Type type) { ... }

  public ILog GetLogger(string name) { ... }
}</programlisting></para>

      <para>For convenience, <classname>Common.Logging</classname> comes with
      an abstract base class
      <classname>Common.Logging.Factory.AbstractCachingLoggerFactoryAdapter</classname>
      for easier implemention of factory adapters and
      <classname>Common.Logging.Factory.AbstractLogger</classname> for
      implementing loggers.</para>

      <para></para>
    </section>

    <section>
      <title>Bridging logging systems</title>

      <para>In the case your application uses frameworks that are tied to
      different logging systems, one usually had to find a workaround
      yourself. Using Common.Logging removes this problem: All integration
      modules come with plugs to route log messages in 2 directions - either
      send messages from Common.Logging to the 3rd party logging system, or
      you can feed messages from that other logging system into
      Common.Logging.</para>

      <para>Let's assume, one of your frameworks uses log4net, another one
      System.Diagnostics.Trace. You prefer the small but powerful NLog system.
      First you need to configure log4net to send all log events to
      Common.Logging:</para>

      <para><example>
          <title>Route log4net messages to Common.Logging</title>

          <para><programlisting language="myxml">&lt;log4net&gt;
    &lt;appender name="CommonLoggingAppender"
              type="Common.Logging.Log4Net.CommonLoggingAppender, Common.Logging.Log4Net"&gt;
        &lt;layout type="log4net.Layout.PatternLayout, log4net"&gt;
            &lt;param name="ConversionPattern" value="%level - %class.%method: %message" /&gt;
        &lt;/layout&gt;
    &lt;/appender&gt;

    &lt;root&gt;
        &lt;level value="ALL" /&gt;
        &lt;appender-ref ref="CommonLoggingAppender" /&gt;
    &lt;/root&gt;
&lt;/log4net&gt;
</programlisting>To get System.Diagnostics.Trace messages routed to
          Common.Logging, you need to configure the corresponding
          CommonLoggingTraceListener:</para>

          <para><example>
              <title>Route System.Diagnostics.Trace messages to
              Common.Logging</title>

              <para><programlisting language="myxml">&lt;system.diagnostics&gt;
  &lt;sharedListeners&gt;
    &lt;add name="Diagnostics"
         type="Common.Logging.Simple.CommonLoggingTraceListener, Common.Logging"
         initializeData="DefaultTraceEventType=Information; LoggerNameFormat={listenerName}.{sourceName}"&gt;
      &lt;filter type="System.Diagnostics.EventTypeFilter" initializeData="Information"/&gt;
    &lt;/add&gt;
  &lt;/sharedListeners&gt;
  &lt;trace&gt;
    &lt;listeners&gt;
      &lt;add name="Diagnostics" /&gt;
    &lt;/listeners&gt;
  &lt;/trace&gt;
&lt;/system.diagnostics&gt;
</programlisting>Finally you want Common.Logging to output all events to
              NLog:</para>
            </example><example>
              <title>Route Common.Logging messages to NLog</title>

              <para><programlisting language="myxml">&lt;nlog autoReload="true" throwExceptions="true"&gt;
 &lt;targets&gt;
  &lt;target name="common.logging"
          type="Common.Logging.NLog.CommonLoggingTarget, Common.Logging.NLog"
          layout="${longdate}|${level:uppercase=true}|${message}"
          filename="C:\temp\${date:format=yyyy-MM-dd}_logA.txt"/&gt;
 &lt;/targets&gt;
 &lt;rules&gt;
  &lt;logger name="*" minlevel="Info" writeTo="common.logging" /&gt;
 &lt;/rules&gt;
&lt;/nlog&gt;
</programlisting></para>
            </example></para>
        </example></para>

      <para></para>
    </section>
  </section>
</chapter>
